Hero Animation in Flutter
Hero Animation is a Flutter animation technique used to smoothly move a widget from one screen (route) to another. It is commonly used for images, product cards, profile pictures, icons, and other visual elements that appear on both screens.
Hero animations are also known as shared element transitions. The main idea is that an element appears to "fly" from its position on the first screen to its corresponding position on the second screen.
1. What is Hero Animation?
A Hero animation connects two widgets located on two different routes. The widgets are wrapped inside the Hero widget and use the same tag.
When the user navigates from the first route to the second route, Flutter automatically animates the matching Hero widget between the two positions.
Hero(
tag: 'product-image',
child: Image.asset('assets/product.png'),
)
The same Hero tag must be used on the source and destination screens.
2. Why Use Hero Animation?
Hero animations provide a visual connection between screens and help users understand where an item came from and where it went.
- Creates smooth page-to-page transitions.
- Improves visual continuity.
- Helps users understand navigation context.
- Creates polished and modern user interfaces.
- Works especially well with images and product cards.
- Can animate position and size between routes.
- Can be combined with other Flutter animations.
3. Common Use Cases
| Use Case |
Example |
| Product image |
Thumbnail expands into product detail image. |
| Profile picture |
Small avatar moves to a large profile image. |
| Gallery |
Thumbnail moves to full-screen image. |
| News application |
Article thumbnail moves to article detail page. |
| Social media |
Post image moves to a detailed post screen. |
| Shopping application |
Product image transitions into product details. |
| Music application |
Album artwork moves to a player screen. |
4. Basic Structure of a Hero Animation
A basic Hero animation requires two Hero widgets:
- A Hero on the source route.
- A Hero on the destination route.
- Both Hero widgets must use the same tag.
- The destination route must be pushed using navigation.
Source Screen
↓
Hero(tag: 'image')
↓
Navigator.push()
↓
Destination Screen
↓
Hero(tag: 'image')
Flutter detects the matching tags and performs the Hero transition between the two positions.
5. Hero Widget Syntax
Hero(
tag: 'uniqueTag',
child: YourWidget(),
)
Important Properties
tag - Identifies the Hero and connects the source and destination widgets.
child - The widget that participates in the Hero animation.
createRectTween - Allows customization of the rectangle interpolation used during the flight.
flightShuttleBuilder - Allows customization of the widget displayed during the Hero flight.
placeholderBuilder - Allows customization of the placeholder left in the source route during the flight.
transitionOnUserGestures - Controls whether the Hero transition participates in user gesture-driven route transitions.
6. Understanding the Hero Tag
The tag is the most important part of a basic Hero animation. It identifies which Hero on the source route corresponds to which Hero on the destination route.
Hero(
tag: 'imageHero',
child: Image.network(
'https://picsum.photos/250',
),
)
On the destination screen:
Hero(
tag: 'imageHero',
child: Image.network(
'https://picsum.photos/250',
),
)
Both widgets use the same value:
tag: 'imageHero'
Therefore, Flutter can associate them with each other.
7. Tag Must Be Unique in the Route
When using Hero animations, Hero tags should identify the corresponding elements correctly. Having multiple Heroes with the same tag in the same route can cause problems because Flutter needs to determine which Hero participates in the transition.
For lists of items, use a unique identifier for each item.
Hero(
tag: 'product-${product.id}',
child: Image.network(product.imageUrl),
)
This approach is useful when displaying multiple products.
8. Simple Hero Animation Example
The following example demonstrates an image moving from one screen to another.
import 'package:flutter/material.dart';
void main() {
runApp(const HeroApp());
}
class HeroApp extends StatelessWidget {
const HeroApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Hero Animation',
home: const HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home Screen'),
),
body: Center(
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DetailScreen(),
),
);
},
child: Hero(
tag: 'imageHero',
child: Image.network(
'https://picsum.photos/250',
width: 200,
height: 200,
fit: BoxFit.cover,
),
),
),
),
);
}
}
class DetailScreen extends StatelessWidget {
const DetailScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Detail Screen'),
),
body: Center(
child: Hero(
tag: 'imageHero',
child: Image.network(
'https://picsum.photos/250',
width: 350,
height: 350,
fit: BoxFit.cover,
),
),
),
);
}
}
How This Example Works
- The first screen displays an image.
- The image is wrapped inside a Hero widget.
- The Hero uses the tag
imageHero.
- The user taps the image.
Navigator.push() opens the detail screen.
- The detail screen contains another Hero with the same tag.
- Flutter detects the matching Hero widgets.
- The image smoothly moves and changes size between the two screens.
9. Hero Animation Flow
Home Screen
↓
User taps image
↓
Navigator.push()
↓
Flutter finds matching Hero tags
↓
Hero starts flying
↓
Position and size are interpolated
↓
Destination screen appears
↓
Hero reaches destination
When returning to the previous screen using Navigator.pop(), the Hero animation can run in the reverse direction.
10. Hero Animation Between Different Sizes
The source and destination Hero widgets do not have to have the same size.
For example, an image can start as a small thumbnail:
Hero(
tag: 'productImage',
child: SizedBox(
width: 80,
height: 80,
child: Image.asset(
'assets/product.png',
fit: BoxFit.cover,
),
),
)
And appear as a large image on the destination screen:
Hero(
tag: 'productImage',
child: SizedBox(
width: 350,
height: 350,
child: Image.asset(
'assets/product.png',
fit: BoxFit.cover,
),
),
)
Flutter animates the Hero's bounds from the starting rectangle to the destination rectangle.
11. Hero Animation with a Product Card
Hero animations are frequently used in shopping applications.
Hero(
tag: 'product-101',
child: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.asset(
'assets/shoes.png',
width: 150,
height: 150,
fit: BoxFit.cover,
),
),
)
On the product details page:
Hero(
tag: 'product-101',
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.asset(
'assets/shoes.png',
width: 350,
height: 350,
fit: BoxFit.cover,
),
),
)
This creates a natural transition from the product thumbnail to the large product image.
12. Hero Animation with ListView
Hero animations can be used with lists and grids. Each item should have a unique Hero tag.
ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
final product = products[index];
return ListTile(
leading: Hero(
tag: 'product-${product.id}',
child: Image.network(
product.imageUrl,
width: 60,
height: 60,
fit: BoxFit.cover,
),
),
title: Text(product.name),
);
},
)
When the user selects a product, the same tag can be used on the product detail page.
13. Hero Animation with GestureDetector
GestureDetector can be used to trigger navigation when the Hero is tapped.
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DetailScreen(),
),
);
},
child: Hero(
tag: 'profileImage',
child: Image.asset(
'assets/profile.jpg',
width: 100,
height: 100,
),
),
)
14. Hero Animation with InkWell
InkWell is useful when the Hero is part of a Material-based interactive UI.
Hero(
tag: 'product',
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DetailScreen(),
),
);
},
child: Image.asset(
'assets/product.png',
),
),
),
)
The Material wrapper can help preserve expected Material visual behavior during interaction.
15. Hero Animation with Navigator.push()
Hero transitions are triggered when navigation changes the route stack.
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DetailScreen(),
),
);
When the new route contains a matching Hero, Flutter performs the Hero transition.
16. Hero Animation with Navigator.pop()
When returning to the previous route, the Hero can animate back.
Navigator.pop(context);
The matching Hero on the destination and source routes allows Flutter to perform the reverse transition.
17. Understanding Source and Destination Heroes
Source Hero
The Hero widget currently visible on the route from which navigation starts is called the source Hero.
Destination Hero
The corresponding Hero widget on the new route is the destination Hero.
Source Route
Hero(
tag: 'photo',
child: Image.asset('assets/photo.png'),
)
↓ Navigator.push()
Destination Route
Hero(
tag: 'photo',
child: Image.asset('assets/photo.png'),
)
18. How Flutter Performs the Hero Flight
During a Hero transition, Flutter calculates the starting and ending bounds of the Hero. The Hero is temporarily displayed in an overlay during the flight so that it can visually move above the routes.
The simplified process is:
- The source Hero is identified.
- The destination Hero is identified using the matching tag.
- Flutter calculates the source and destination rectangles.
- The Hero is placed in the overlay during the flight.
- The Hero moves toward the destination position and size.
- The destination route becomes visible around the transition.
- At the end of the flight, the Hero is placed in its destination route.
19. Hero Animation and Route Transitions
Hero animations work together with route transitions. When a destination route is pushed, the Hero moves between the matching elements while the rest of the destination route transitions into view.
This creates a visual relationship between the old screen and the new screen instead of making the new screen appear completely disconnected.
20. Hero Animation with Circle to Rectangle
A Hero animation can also be customized so that an element changes shape while moving between screens. A common example is transforming a circular profile image into a rectangular or square image on the destination screen.
Hero(
tag: 'profile',
child: ClipOval(
child: Image.asset(
'assets/profile.jpg',
width: 100,
height: 100,
fit: BoxFit.cover,
),
),
)
The destination can use a different clipping structure while keeping the same Hero tag.
21. Radial Hero Animation
A radial Hero animation is a more advanced Hero effect in which the Hero can appear to transform between circular and rectangular shapes while flying between routes.
This type of animation can use custom rectangle tweening and clipping techniques to control the transformation.
For advanced radial Hero animations, Flutter documentation demonstrates techniques involving clipping and MaterialRectCenterArcTween.
22. Customizing the Hero Flight Path
By default, Flutter calculates a Hero flight path using a rectangle tween. The createRectTween property can be used to provide a custom RectTween.
Hero(
tag: 'photo',
createRectTween: (begin, end) {
return MaterialRectCenterArcTween(
begin: begin,
end: end,
);
},
child: Image.asset(
'assets/photo.png',
),
)
This technique can be useful when the default Hero movement does not match the desired design.
23. What is RectTween?
RectTween is used to interpolate between two rectangles. In a Hero animation, the rectangles represent the Hero's starting and ending bounds.
RectTween(
begin: beginRect,
end: endRect,
)
The tween calculates intermediate rectangle values during the animation.
24. MaterialRectArcTween
Flutter's standard Hero behavior uses a rectangle tween that produces a curved motion. The default behavior uses MaterialRectArcTween for the Hero's bounds.
This allows the Hero to follow a natural curved path rather than simply moving in a straight line.
25. MaterialRectCenterArcTween
MaterialRectCenterArcTween is another rectangle tween that can be used for specialized Hero motion. It interpolates using the center of the rectangles and can help maintain the desired aspect-ratio behavior in certain radial Hero effects.
Hero(
tag: 'photo',
createRectTween: (begin, end) {
return MaterialRectCenterArcTween(
begin: begin,
end: end,
);
},
child: const SizedBox(
child: Placeholder(),
),
)
26. Custom Hero Flight Widget
The flightShuttleBuilder property allows developers to customize the widget displayed while the Hero is flying between routes.
Hero(
tag: 'profile',
flightShuttleBuilder: (
flightContext,
animation,
flightDirection,
fromHeroContext,
toHeroContext,
) {
return const Material(
color: Colors.transparent,
child: Icon(
Icons.person,
size: 80,
),
);
},
child: const Icon(
Icons.person,
size: 50,
),
)
This is useful when the widget shown during the flight should differ from the normal source or destination representation.
27. Placeholder During Hero Animation
The placeholderBuilder property can customize what remains in the source route while the Hero is participating in the transition.
Hero(
tag: 'photo',
placeholderBuilder: (context, size, child) {
return SizedBox(
width: size.width,
height: size.height,
);
},
child: Image.asset(
'assets/photo.png',
),
)
28. Hero Animation with a Reusable Widget
For larger applications, it is useful to create a reusable widget that contains the Hero implementation.
class ProductHero extends StatelessWidget {
const ProductHero({
super.key,
required this.tag,
required this.image,
required this.size,
});
final String tag;
final String image;
final double size;
@override
Widget build(BuildContext context) {
return Hero(
tag: tag,
child: ClipRRect(
borderRadius: BorderRadius.circular(16),
child: Image.asset(
image,
width: size,
height: size,
fit: BoxFit.cover,
),
),
);
}
}
The same component can then be used on different screens with the same tag.
29. Hero Animation in a Shopping App
A typical shopping flow looks like this:
Product Grid
↓
Small Product Image
↓
User taps product
↓
Navigator.push()
↓
Hero Animation
↓
Large Product Image
↓
Product Details
This creates a strong visual connection between the product selected by the user and its detailed representation.
30. Hero Animation in a Profile Screen
Profile images are another common use case.
Hero(
tag: 'profile-avatar',
child: CircleAvatar(
radius: 30,
backgroundImage: AssetImage(
'assets/profile.jpg',
),
),
)
On the profile screen:
Hero(
tag: 'profile-avatar',
child: CircleAvatar(
radius: 120,
backgroundImage: AssetImage(
'assets/profile.jpg',
),
),
)
The avatar can visually grow into a larger profile image.
31. Hero Animation with GridView
GridView.builder(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
),
itemCount: images.length,
itemBuilder: (context, index) {
return Hero(
tag: 'image-$index',
child: Image.asset(
images[index],
fit: BoxFit.cover,
),
);
},
)
Each item receives a unique tag such as image-0, image-1, and so on.
32. Hero Animation and MaterialApp
Hero animations are typically used inside applications that use Flutter's route and Navigator system.
MaterialApp(
home: const HomeScreen(),
)
Routes can be pushed using Navigator.push(), which allows Flutter to coordinate matching Hero widgets between routes.
33. Hero Animation and Cupertino Routes
Hero animations are not limited to Material page navigation. Flutter's route system can also be used with Cupertino-style navigation.
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => const DetailScreen(),
),
);
The important requirement remains that the source and destination routes contain matching Hero tags.
34. Hero Animation and PageRouteBuilder
For more customized route transitions, you can use PageRouteBuilder along with Hero animations.
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (
context,
animation,
secondaryAnimation,
) {
return const DetailScreen();
},
transitionsBuilder: (
context,
animation,
secondaryAnimation,
child,
) {
return FadeTransition(
opacity: animation,
child: child,
);
},
),
);
This allows the rest of the page transition to be customized while the Hero handles the shared element movement.
35. Hero Animation with Multiple Elements
An application can contain multiple Hero widgets, provided their tags correctly identify the corresponding elements.
Hero(
tag: 'product-image',
child: Image.asset('assets/product.png'),
)
Hero(
tag: 'product-title',
child: const Text('Flutter Shoes'),
)
Multiple matching Hero pairs can participate in the same route transition.
36. Hero Animation with Different Widget Trees
The source and destination Hero widgets can represent the same conceptual element with different layouts. However, keeping the Hero child structures reasonably compatible generally produces more predictable visual transitions.
For example, a small image on one route can become a larger image inside a different layout on another route.
37. Hero Animation and Image Loading
When using network images, make sure the source and destination can display the expected image consistently.
Hero(
tag: 'network-image',
child: Image.network(
imageUrl,
width: 150,
height: 150,
fit: BoxFit.cover,
),
)
For production applications, handle image loading and error states appropriately.
38. Hero Animation and Assets
For local images, add the asset to pubspec.yaml:
flutter:
assets:
- assets/images/
Then use the image in both Hero widgets:
Image.asset(
'assets/images/product.png',
)
39. Hero Animation Debugging
Hero animations can sometimes be difficult to understand because the transition happens quickly. During development, you can slow the animation down to inspect the movement.
import 'package:flutter/scheduler.dart';
void main() {
timeDilation = 5.0;
runApp(const MyApp());
}
A higher timeDilation value slows animations for debugging and visual inspection. It should generally not be used as a normal production setting.
40. Common Hero Animation Problems
Problem 1: Different Tags
// Source
Hero(
tag: 'image1',
child: Image.asset('assets/photo.png'),
)
// Destination
Hero(
tag: 'image2',
child: Image.asset('assets/photo.png'),
)
These tags do not match, so the two Heroes cannot form the intended pair.
Problem 2: Duplicate Tags
Multiple Heroes with the same tag in the same route can create conflicts.
Problem 3: Hero Missing on Destination
If the destination route does not contain a matching Hero, the expected shared element transition cannot occur.
Problem 4: Incorrect Navigation Flow
The Hero transition is associated with route changes, so ensure that the destination route is actually pushed or popped through the Navigator.
Problem 5: Unexpected Visual Shape
Differences between the source and destination widget structures can produce an unexpected flight appearance. Use compatible widget structures or customize the flight behavior when needed.
41. Hero Animation Best Practices
- Use meaningful and unique Hero tags.
- Use stable identifiers for dynamic lists.
- Keep source and destination Hero content conceptually consistent.
- Use Hero animations for meaningful visual relationships.
- Do not animate every widget between every screen.
- Keep Hero transitions short enough to maintain responsiveness.
- Test both forward and reverse navigation.
- Test Hero animations on different screen sizes.
- Handle image loading and error states properly.
- Use custom flight builders only when the default transition is insufficient.
42. Hero Animation vs AnimatedContainer
| Hero |
AnimatedContainer |
| Designed for transitions between routes. |
Designed for implicit property animations. |
| Connects widgets on different screens. |
Usually animates changes within a widget tree. |
| Uses matching tags. |
Uses changed property values. |
| Works with Navigator route transitions. |
Does not require route navigation. |
| Commonly used for images and shared elements. |
Commonly used for size, color, padding, decoration, and layout changes. |
43. Hero Animation vs Page Transition
| Hero Animation |
Page Transition |
| Animates a specific shared element. |
Animates the route/page itself. |
| Connects matching widgets. |
Controls how a route enters or leaves. |
| Requires matching Hero tags. |
Can use MaterialPageRoute, CupertinoPageRoute, or PageRouteBuilder. |
| Useful for images, cards, and icons. |
Useful for fade, slide, scale, and other page transitions. |
44. Complete Practical Product Hero Example
import 'package:flutter/material.dart';
void main() {
runApp(const ProductApp());
}
class ProductApp extends StatelessWidget {
const ProductApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: const ProductHome(),
);
}
}
class ProductHome extends StatelessWidget {
const ProductHome({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Products'),
),
body: Center(
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const ProductDetails(),
),
);
},
child: Hero(
tag: 'product-shoes',
child: ClipRRect(
borderRadius: BorderRadius.circular(16),
child: Image.network(
'https://picsum.photos/400',
width: 180,
height: 180,
fit: BoxFit.cover,
),
),
),
),
),
);
}
}
class ProductDetails extends StatelessWidget {
const ProductDetails({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Product Details'),
),
body: Column(
children: [
const SizedBox(height: 30),
Hero(
tag: 'product-shoes',
child: ClipRRect(
borderRadius: BorderRadius.circular(24),
child: Image.network(
'https://picsum.photos/400',
width: 350,
height: 350,
fit: BoxFit.cover,
),
),
),
const SizedBox(height: 30),
const Text(
'Flutter Product',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 10),
const Text(
'Product details are displayed here.',
),
],
),
);
}
}
What You Learn From This Example
- Creating a Hero widget.
- Using a matching Hero tag.
- Connecting two routes.
- Using
Navigator.push().
- Animating an image between different sizes.
- Returning to the previous screen with reverse Hero navigation.
45. Practical Project Ideas
Project 1: Product Gallery
Create a grid of product images. When the user taps an image, use a Hero animation to display the selected product on a detail page.
Project 2: Profile Viewer
Display small profile avatars and animate the selected avatar into a large profile image.
Project 3: Photo Gallery
Display image thumbnails and use Hero animations when opening the full-screen image viewer.
Project 4: News Application
Animate article thumbnails from the news list into the article details screen.
Project 5: E-Commerce Application
Use Hero animations for product images, then display product information, pricing, and purchasing controls on the details screen.
46. Recommended Development Process
- Identify the element that should visually connect both screens.
- Wrap the source widget with a Hero.
- Choose a meaningful unique tag.
- Wrap the corresponding destination widget with a Hero.
- Use exactly the same tag.
- Navigate using the Navigator.
- Test the forward animation.
- Test the reverse animation.
- Adjust the source and destination sizes and layouts.
- Customize the flight path only when necessary.
47. Interview Questions
Q1. What is Hero animation in Flutter?
Hero animation is a shared element transition that animates a widget from one route to another.
Q2. Which widget is used to create a Hero animation?
The Hero widget is used to create Hero animations.
Q3. What is the purpose of the Hero tag?
The tag identifies the Hero and connects the source Hero with the corresponding destination Hero.
Q4. Should the Hero tag be the same on both screens?
Yes. The source and destination Hero widgets must have matching tags for the intended transition.
Q5. What triggers a Hero animation?
A route transition, such as pushing or popping a route through the Navigator, triggers the Hero animation when matching Heroes are present.
Q6. Can Hero animate between different sizes?
Yes. Flutter can animate the Hero's bounds between different starting and ending sizes.
Q7. Can Hero be used with a ListView?
Yes. Hero animations can be used in lists and grids, but each item should have an appropriate unique tag.
Q8. What is flightShuttleBuilder?
It allows developers to customize the widget displayed during the Hero's flight between routes.
Q9. What is createRectTween?
It allows developers to customize how the Hero's rectangular bounds are interpolated during the transition.
Q10. What is a shared element transition?
A shared element transition is an animation pattern where an element visually moves between two screens while maintaining a relationship between its source and destination representations.
48. Quick Revision
- Hero is used for shared element transitions between routes.
- Hero animations commonly connect images, cards, icons, and profile pictures.
- The source and destination Heroes need matching tags.
- Route navigation triggers the transition.
Navigator.push() can trigger the forward Hero animation.
Navigator.pop() can trigger the reverse Hero animation.
- Hero can animate position and size between routes.
createRectTween can customize the Hero flight path.
flightShuttleBuilder can customize the widget during flight.
placeholderBuilder can customize the placeholder.
- Unique tags are important when using multiple Hero widgets.
- Hero animations are particularly useful for product, profile, gallery, and news applications.
49. Learning Outcome
After studying Hero Animation in Flutter, you should be able to:
- Explain the concept of Hero animation.
- Understand shared element transitions.
- Use the Hero widget.
- Create matching Hero tags.
- Animate images between screens.
- Animate widgets between different sizes.
- Use Hero animations with ListView and GridView.
- Use Hero animations with product cards.
- Use Hero animations with profile images.
- Understand source and destination Heroes.
- Understand the Hero flight process.
- Customize Hero flight behavior when required.
- Identify and fix common Hero animation problems.
50. JustAcademy Flutter Resources
Learn more about Flutter development through the following resources:
51. Summary
Hero Animation is a powerful Flutter technique for creating smooth transitions between routes. By placing matching Hero widgets on the source and destination screens and giving them the same tag, Flutter can animate the shared element between its starting and ending positions.
Hero animations are especially useful for product images, profile pictures, galleries, news cards, and other interfaces where the user should clearly understand the relationship between an item and its detailed screen. For basic transitions, the Hero widget requires very little code, while advanced features such as createRectTween, flightShuttleBuilder, and custom clipping can be used for more specialized animation effects.